<?php

namespace App\Models;

use App\BtApi;
use App\Helper;
use App\Telnet;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;

class ServerV2 extends Server
{
    /**
     * @param $command
     * @return array
     */
    private static $mod_sep=',';

//    public function getModsAttribute($value)
//    {
////        return 'aaa';
////        if (!$value) return ['eluna'];
//        return explode( self::$mod_sep ,trim($value));
//    }
//    public function setModsAttribute($value)
//    {
//        if (in_array('eluna',$value))
//            $this->attributes['mods'] =implode(self::$mod_sep,$value);
//        else
//            $this->attributes['mods'] ='eluna'.self::$mod_sep.implode(self::$mod_sep,$value);
//    }

    /**
     * @return bool|false|resource
     */
    private function getConn(){
        try {
            $connection = ssh2_connect($this->server_host,$this->root_port??22);
            if (ssh2_auth_password($connection,"root",$this->root_pwd))
            {
                return $connection;
            }
        }catch(Exception $ex){
            return false;
        }
        return false;
    }

    private function run_exec($command,$conn=null,$br=true,$time=20){
//        $ssh2=new SSH2();
//        $ssh2->connect("root",$this->root_pwd,$this->server_host,22);
//
//        if (is_array($command)){
//            $ssh2->shell();
//            $ssh2->execInteractive($command);
//        }elseif(is_string($command)){
//            $ssh2->exec($command);
//        }
//        $res=$ssh2->get();
//        return $res;
//        $res='';
        $connection=$conn??$this->getConn();
        if ($connection)
        {
            $stream = ssh2_exec($connection, $command);
            stream_set_timeout($stream, $time);
            stream_set_blocking($stream,true);
            $res='';

            while($o=fgets($stream)){
                if ($br)
                    $res .= $o.'<br>';
                else
                    $res .= $o;
            }

            return $res;
        }else{
            return false;
        }
    }

    /**
     * 向服务器发送文件
     * @param $infile
     * @param $remotefile
     * @param null $conn
     * @return bool
     */
    private function run_send($infile,$remotefile,$conn=null){
        $connection=$conn??$this->getConn();
        if ($connection)
        {
            if(ssh2_scp_send($connection, $infile, $remotefile, 0644))
                return true;
            else
                return false;
        }else{
            return false;
        }
    }

    private function run_getFile(string $path){
        $connection=$conn??$this->getConn();
        $sftp = ssh2_sftp($connection);
        $content = file_get_contents("ssh2.sftp://" . intval($sftp).$path);
        return $content;
    }

    public function serverTest() :array{
        $re=$this->run_exec('uname -v');
        if ($re===false){
            return ['res'=>0,'msg'=>'连接服务器失败，请检查IP地址是否正确，或者服务器是否开启','data'=>''];
        }
        $msg='';
        if (strpos($re,'Ubuntu')!==false /*|| strpos($re,'Debian')!==false*/){  //[Errno 11001] getaddrinfo failed
            return ['res'=>1,'msg'=>'success','data'=>substr($re,2,-3)];
        }else if (strpos($re,'[Errno 11001]')!==false){  //[Errno 11001] getaddrinfo failed
            $msg=('连接服务器失败，请检查IP地址是否正确');
        }else if(strpos($re,'[WinError 10060]')!==false){  //[WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。
            $msg=('连接服务器失败，请检查IP地址是否正确，或者服务器是否开启');
        }else if(strpos($re,'Authentication')!==false){  //Authentication failed.
            $msg=('鉴权失败，请检查root密码是否正确');
        }else if(strpos($re,'[Errno None]')!==false){  //[Errno None] Unable to connect to port 22 on 103.39.226.33
            $msg=('连接服务器失败，请检查IP地址是否正确，或者服务器是否开启');
        }else{
            $msg=("不支持的系统");
        }

        return ['res'=>0,'msg'=>$msg,'data'=>$re];
    }
    public function getPWDInfo(){
        $re=$this->run_exec('cat ~/install_pwd.lock',$conn=null,$br=false);
//        返回  空，或者  ‘xxxxxxx/n’
        return ['res'=>0,'data'=>$re];
    }
    public function getInstallInfo(){
//        $re=$this->getPWDInfo();

        $re=$this->run_exec('cat ~/install.lock');
        $step=0;
        $res=0;
        if ($re===''){
            $res=0;  //未安装
        }elseif (strpos($re,'success')!==false){
            $step=100;
            $res=3;  //全部成功
        }elseif (strpos($re,'90%')!==false){
            $step=90;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'80%')!==false){
            $step=80;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'70%')!==false){
            $step=70;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'60%')!==false){
            $step=60;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'50%')!==false){
            $step=50;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'40%')!==false){
            $step=40;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'30%')!==false){
            $step=30;
            $res=2;  //宝塔安装成功
        }elseif (strpos($re,'20%')!==false){
            $step=20;
            $res=2;  //宝塔安装成功
        }else{
            $step=10;
            $res=1;  //安装中
        }
//        if ($step>20) $this->setBTUrl();
        return ['res'=>$res,'data'=>str_replace('\n','<br>',$re)];
    }

    public function runSQLFile($fileName){
        $pwd = $this->db_pwd;
        $connection=$this->getConn();

//        return storage_path("app/public/sql/{$fileName}.zip");
        $this->run_send(storage_path("app/public/sql/{$fileName}.zip"), "/root/{$fileName}.zip" ,$connection);
        $command="unzip -q {$fileName}.zip && mysql -uroot -p{$pwd} -Dacore_world < /root/{$fileName}.sql && rm /root/{$fileName}*";

        $re=$this->run_exec($command,$connection,true,30);
        return ['res'=>0,'data'=>$re];
    }

    public function installAll(){
//        $ip = $this->server_host;
//        $pwd2 = $this->db_pwd;
//        $name = $this->name;
//        $tokens=['',Helper::getRandStr()];
//        $tokens[0]=md5($tokens[1]);
//        $this->bt_key=$tokens[1];
        $this->soap_pwd='';  //清空GM密码，为了后面可以重新生成~
        $this->save();
        Player::where('server_id',$this->id)->delete();
        PlayerMoneyLog::where('server_id',$this->id)->delete();
//        $mods=$this->mods;
        $t=$this->version;
        $v=config("conf.CoreVer")['S'.$this->type]['C'.$this->version];
        $connection=$this->getConn();
//        $this->run_send(public_path("initAZ/v2ray.json"), "/usr/local/proxy.json" ,$connection);
        $this->run_send(public_path("initAZ/install.sh"), "/root/server_install.sh" ,$connection);
//        $command ="apt-get install -y tmux && tmux kill-session -t install  && tmux new-session -d -s install && tmux send-keys -t install 'bash server_install.sh {$pwd2} {$name} {$v}' C-m";

        $command="
if ! type tmux >/dev/null 2>&1; then
	apt install -y tmux;
else
    tmux kill-session -t install;
    sleep 1s
fi
tmux new-session -d -s install;
tmux send-keys -t install 'cd /root && sh server_install.sh $t $v' C-m;
";

        $re=$this->run_exec($command,$connection);
        return ['res'=>0,'data'=>[$command,$re]];
    }
    public function serverUpdate(){
        $mods=$this->mods;
        $t=$this->version;
        $v=config("conf.CoreVer")['S'.$this->type]['C'.$this->version];
        $connection=$this->getConn();
        $this->run_send(public_path("initAZ/update.sh"), "/root/server_update.sh",$connection);
        $command ="
tmux kill-session -t install
sleep 1s
tmux new-session -d -s install
tmux send-keys -t install 'cd /root && sh server_update.sh $t $v' C-m";
        $re=$this->run_exec($command,$connection);
        return ['res'=>0,'data'=>$re];
    }

//    public function serverUpdate(){
//        $command ="
//if tmux has-session -t install 2>/dev/null; then
//    tmux send-keys -t install  'echo 'startUpdate...' > ~/install.lock && cd /azerothcore && git pull && /azerothcore/acore.sh compiler all && echo 'success' >> ~/install.lock && echo 'success' >> ~/install_success.lock' C-m
//else
//    tmux new-session -d -s install && tmux send-keys -t install  'echo 'startUpdate...' > ~/install.lock && cd /azerothcore && git pull && /azerothcore/acore.sh compiler all && echo 'success' >> ~/install.lock && echo 'success' >> ~/install_success.lock' C-m
//fi
//";
//        $re=$this->run_exec($command);
//        return ['res'=>0,'data'=>$re];
//    }

    public function serverPull(){
        $command ="tmux send-keys -t install  'cd /azerothcore && git pull' C-m";
        $re=$this->run_exec($command);
        return ['res'=>0,'data'=>$re];
    }
//    public function getBT(){
//        $re=$this->run_exec('bt default');
//        $re=str_replace('\n','',$re);
//        return ['res'=>0,'data'=>$re];
//    }

//    public function checkBTAPI(){
//        $bt=new BtApi($this->bt_url,$this->bt_key);
//        $data = $bt->GetSystemTotal();
//        return ['res'=>0,'data'=>$data];
//    }

    public function serverStatus(){
        $re=$this->run_exec('tmux ls');
        $res=0;
        if (strpos($re,'world-session')!==false){
            $res=1;  //启动
        }else{
            $res=0;  //未启动
        }
        return ['res'=>$res,'data'=>$re];
    }
    public function serverStart(){
        //适配镜像服务器，设置一次realmlist
        Helper::setDataBaseConf('mysql_auth',$this,'acore_auth');
        Realmlist::where('id',1)->update([
            'name'=>$this->name,
            'address'=>$this->server_host
        ]);

        $command="
tmux new-session -d -s world-session
tmux send-keys -t world-session '/azerothcore/env/dist/simple-restarter /azerothcore/env/dist/bin worldserver' C-m
tmux new-session -d -s auth-session
tmux send-keys -t auth-session 'sleep 3s && /azerothcore/env/dist/simple-restarter /azerothcore/env/dist/bin authserver' C-m
";
        $re=$this->run_exec($command);

        return ['res'=>0,'data'=>$re];
    }
    public function serverStop(){
        $re=$this->run_exec('
pid=`lsof -i:7878 -t`
if [ ! -z "$pid" ]; then
	ppid=$(awk "/PPid/{print $2}" /proc/$pid/status)
	if [[ $ppid != 1 ]]; then
	    kill -9 $ppid
	fi
  	kill $pid
fi
pid=`lsof -i:3724 -t`
if [ ! -z "$pid" ]; then
	ppid=$(awk "/PPid/{print $2}" /proc/$pid/status)
	if [[ $ppid != 1 ]]; then
	    kill -9 $ppid
	fi
  	kill $pid
fi
pid=`lsof -i:8085 -t`
if [ ! -z "$pid" ]; then
	ppid=$(awk "/PPid/{print $2}" /proc/$pid/status)
	if [[ $ppid != 1 ]]; then
	    kill -9 $ppid
	fi
  	kill $pid
fi
sleep 1s
tmux kill-session -t world-session
tmux kill-session -t auth-session
');
        return ['res'=>0,'data'=>$re];
    }

    public function setAdmin(){
        if($this->soap_pwd) return;
        $pwd2 = $this->db_pwd;
        $this->soap_acc='ADMIN';
        $this->soap_pwd=$pwd2;
        $this->save();
//        $re=$this->run_exec('tmux send-keys -t world-session "account creat admin '.$pwd2.'" C-m');

//        //如果GM账号不完整
////        if($this->soap_acc && $this->soap_pwd) return;
//        // 每次启动都执行
//        $pwd2 = $this->db_pwd;
//        $this->soap_acc='ADMIN';
//        if (!$this->soap_pwd)
//            $this->soap_pwd=$this->db_pwd;
//        $pwd=$this->soap_pwd;
//        $this->save();
////        创建账号，重置密码
//        $re=$this->run_exec('tmux send-keys -t world-session "account creat admin '.$pwd2.'" C-m && tmux send-keys -t world-session "account set password admin '.$pwd.' '.$pwd.'" C-m && tmux send-keys -t world-session "account set gmlevel admin 3 -1" C-m');
    }

    public function telnet($port):int{
        $res=0;
        try {
            $telnet = new Telnet($this->server_host,$port);
            if (empty($telnet)){
                $res=0;
            } else {
                $res=1;
            }
            $telnet->close();
        } catch(Exception $exception){
            $res=0;
        }
        return $res;
    }

    public function __call($method, $parameters)
    {
        if ($method=='getWorldServerConf'){
            return $this->GetFileBody($this->path.$this->configPath);
        }elseif ($method=='saveWorldServerConf'){
            return $this->SaveFileBody($this->path.$this->configPath,$parameters[0]);
        }elseif ($method=='getLuaList'){
            return $this->GetDir($this->path.$this->luaPath);
        }elseif ($method=='createLuaDir'){
            return $this->CreateDir($this->path.$this->luaPath);
        }elseif ($method=='createLuaFile'){
            return $this->CreateFile($this->path.$this->luaPath.'/'.$parameters[0]);
        }elseif ($method=='saveLuaFile'){
            return $this->SaveFileBody($this->path.$this->luaPath.'/'.$parameters[0],$parameters[1]);
        }elseif ($method=='delLuaFile'){
            return $this->DeleteFile($this->path.$this->luaPath.'/'.$parameters[0]);
        }elseif ($method=='changeLuaName'){

        }elseif ($method=='changeLuaStatus'){
            return $this->MvFile($this->path.$this->luaPath.'/',$parameters[0],$parameters[1]);
        }elseif ($method=='renameLuaFile'){
            return $this->MvFile($this->path.$this->luaPath.'/',$parameters[0],$parameters[1]);
        }elseif($method=='getLuaScript'){
            return $this->GetFileBody($this->path.$this->luaPath.'/'.$parameters[0]);
        }elseif($method=='setLuaScript'){
            return $this->SaveFileBody($this->path.$this->luaPath.'/'.$parameters[0],$parameters[1]);
        }else{
            return parent::__call($method, $parameters);
        }
    }
    function GetFileBody(string $path){
        return ['data'=>$this->run_getFile($path),'status'=>true, 't'=>2];
    }

    function SaveFileBody(string $path,string $data){
        //将string保存到本地，然后上传到服务器
        Storage::put("server/{$this->id}{$path}",$data);
        $path_local=storage_path("app/server/{$this->id}{$path}");
        //上传文件
        $connection=$this->getConn();
        $res=$this->run_send($path_local, $path,$connection);
        return ['msg'=>"文件已保存!",'status'=>$res, 't'=>2];
    }
    function GetDir(string $path){
        $list= $this->run_exec("cd $path && ls *.lua *.lua-",null,false);
        $list=explode("\n",$list);
        return array_slice($list,0,-1);
    }
    function luaList(){
        $res=$this->getLuaList();
        $files=[];
        foreach ($res as $arr){
            $arrName=explode('.',$arr);
            $files[]=[
                'name'=>$arrName[0],
                'type'=>$arrName[1],
                't'=>2
            ];
        }
        return $files;
    }
    function CreateDir(string $path){
        return true;
    }
    function MvFile(string $path,string $nameOld,string $nameNew){
        $res= $this->run_exec("cd $path && mv $nameOld $nameNew");
        return ['msg'=>'重命名成功!','status'=>$res,'t'=>2];
    }
    function CreateFile(string $path){
        $res= $this->run_exec("touch $path");
        return ['msg'=> "文件创建成功!", 'status'=>$res,'t'=>2];
    }
    function DeleteFile(string $path){
        $res= $this->run_exec("rm $path");
        return ['msg'=>'已将文件移动到回收站!','t'=>2];
    }


    public function statusBt(){
        return -1;
    }
    public function statusSSH(){
        $conn=$this->getConn();
        if ($conn)
            return 1;
        else
            return 2;
    }
//    public function statusDB(){
//        return '2DB';
//    }
//    public function statusSOAP(){
//        return '2SOAP';
//    }
}
